#include <dalelib/graphics/camera.h>

namespace dalelib
{

m4& Camera::getModelView()
{
	return _modelview;
}

m4& Camera::getModelViewInv()
{
	return _modelview_inv;
}

m4& Camera::getProjection()
{
	return _projection;
}

m4 Camera::getModelViewProj()
{
	return _projection*_modelview;
}

void Camera::setPerspective(const float _Fov, const float _Aspect, const float _Near, const float _Far)
{
	_is_ortho = false;
	_fov = _Fov;
	_aspect = _Aspect;
	_near = _Near;
	_far = _Far;

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective( _fov, _aspect, _near, _far );
	glGetFloatv( GL_PROJECTION_MATRIX, (float*)_projection.ptr() );
}

void Camera::setOrtho(const float _Left, const float _Right, const float _Top, const float _Bottom, const float _Near, const float _Far)
{
	_is_ortho = true;
	_left = _Left;
	_right = _Right;
	_top = _Top;
	_bottom = _Bottom;
	_near = _Near;
	_far = _Far;

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glOrtho( _left, _right, _bottom, _top, _near, _far  );
	glGetFloatv( GL_PROJECTION_MATRIX, (float*)_projection.ptr() );
}

void Camera::setModelViewIdentity()
{
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

	glGetFloatv(GL_MODELVIEW_MATRIX,(float*)_modelview.ptr());
	_modelview_inv = _modelview.inverse();
}

void Camera::lookAt(v3 _Pos, const v3 _Tgt, const v3 _Up)
{
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	gluLookAt(_Pos[0],_Pos[1],_Pos[2],_Tgt[0],_Tgt[1],_Tgt[2],_Up[0],_Up[1],_Up[2]);

	glGetFloatv(GL_MODELVIEW_MATRIX,(float*)_modelview.ptr());
	_modelview_inv = _modelview.inverse();
//	_modelview_inv = _modelview.fastInverse();

	_ang.fromMatrix(_modelview_inv);
	_pos = _Pos;

}

void Camera::rotate(const v3 _Axis, const float _Angle)
{
	_ang = quat(_Axis,_Angle).unit()*_ang;
}

void Camera::view()
{
	glMatrixMode(GL_PROJECTION);
	glLoadMatrixf((float*)_projection.ptr());
	glMatrixMode(GL_MODELVIEW);
	glLoadMatrixf((float*)_modelview.ptr());
}

void Camera::viewBoundingSphere(const v3 _Tgt,const float _Size,const float _DepthRange)
{
	if( _is_ortho )
	{
		float dist = (_Tgt-_pos).len();
		setOrtho( -_Size, _Size, _Size, -_Size, dist-_DepthRange/2, dist+_DepthRange/2 );
		lookAt(_pos, _Tgt, v3(0,1,0));
	}
	else
	{
		v3 v = _Tgt-_pos;
		float l = v.normalise();
		float fov = rad2deg(asin(_Size/l))*2;
		setPerspective(fov*_aspect, _aspect, l-_Size, l+_Size);
		lookAt(_pos, _Tgt, v3(0,1,0));
	}
}

} // namespace dalelib
